![@react-google-maps/apiを使った地図アプリでマーカーとバルーンの位置関係をいい感じに表示する](https://devio2023-media.developers.io/wp-content/uploads/2021/02/google_map.jpg)
@react-google-maps/apiを使った地図アプリでマーカーとバルーンの位置関係をいい感じに表示する
こんにちは、CX事業本部の若槻です。
前回の記事では@react-google-maps/apiの基本的な動作をReactアプリを実際に起動して確認しました。
今回は、@react-google-maps/apiを使った地図アプリでマーカーとバルーンの位置関係をいい感じに表示する方法を確認してみました。
やりたいこと
下記のように指定の座標位置に配置されたマーカーの上部にバルーンを表示し、マップの拡縮をしてもマーカーとバルーンの相対位置が変わらないようにしたいです。
やってみる
環境作成
前回の下記記事で作成した環境があればそのまま利用可能です。
未作成の場合は下記コマンドを実行してReactプロジェクト作成とパッケージインストールを行います。
% npx create-react-app react-google-maps-api-local --typescript % cd react-google-maps-api-local % npm i @react-google-maps/api % npm i
APIキーの用意
「Maps JavaScript API」を利用可能なGoogle Maps PlatformのAPIキーを用意します。まだの場合は下記を参考に作成してください。
@types/googlemaps導入
下記コマンドを実行して@types/googlemaps
をインストールします。
% npm i @types/googlemaps --save-dev
これによりgoogle.maps.Size()
の型エラーを抑制できます。
App.tsx編集
src/App.tsx
を下記のコードに変更します。
import { useState } from "react"; import { GoogleMap, LoadScript, InfoWindow, Marker, } from "@react-google-maps/api"; const containerStyle = { height: "100vh", width: "100%", }; const center = { lat: 35.69575, lng: 139.77521, }; const positionAkiba = { lat: 35.69731, lng: 139.7747, }; const positionIwamotocho = { lat: 35.69397, lng: 139.7762, }; const divStyle = { background: "white", fontSize: 7.5, }; const MyComponent = () => { const [size, setSize] = useState<undefined | google.maps.Size>(undefined); const infoWindowOptions = { pixelOffset: size, }; const createOffsetSize = () => { return setSize(new window.google.maps.Size(0, -45)); }; return ( <LoadScript googleMapsApiKey="API_KEY" onLoad={() => createOffsetSize()}> <GoogleMap mapContainerStyle={containerStyle} center={center} zoom={17}> <Marker position={positionAkiba} /> <Marker position={positionIwamotocho} /> <InfoWindow position={positionAkiba} options={infoWindowOptions}> <div style={divStyle}> <h1>秋葉原オフィス</h1> </div> </InfoWindow> <InfoWindow position={positionIwamotocho} options={infoWindowOptions}> <div style={divStyle}> <h1>岩本町オフィス</h1> </div> </InfoWindow> </GoogleMap> </LoadScript> ); }; export default MyComponent;
マーカーMarker
とバルーンInfoWindow
は別々のオブジェクトです。<InfoWindow>
でposition
で指定した座標位置からの画面上の絶対距離をoptions
のpixelOffset
により定義することにより、マーカーの上部にバルーンが常に表示されるようにしています。
アプリの起動
Reactアプリを起動します。
% npm run start
マップ上でマーカーとバルーンの位置関係をいい感じに表示できていますね。
useStateをなぜ使う必要があるか
今回のコードでは<InfoWindow>
でoptions
のpixelOffset
の値を直接指定せず、<LoadScript>
のonLoad
オプションのコールバック関数の中でuseState
により作成した変数を介して指定しています。なぜこんな遠回りなことをしているかと言うと、window.google.maps.Size()
は画面上のマップウィンドウ上での絶対距離をもとにSize
オブジェクトを作成するため、マップの読み込み前に実行されるとエラーとなるからです。
よって下記の様にpixelOffset
の値をuseState
を使わず直接指定しようとすると、
const MyComponent = () => { const infoWindowOptions = { pixelOffset: new window.google.maps.Size(0, -45), }; return ( <LoadScript googleMapsApiKey="API_KEY"> <GoogleMap mapContainerStyle={containerStyle} center={center} zoom={17}> <Marker position={positionAkiba} /> <Marker position={positionIwamotocho} /> <InfoWindow position={positionAkiba} options={infoWindowOptions}> <div style={divStyle}> <h1>秋葉原オフィス</h1> </div> </InfoWindow> <InfoWindow position={positionIwamotocho} options={infoWindowOptions}> <div style={divStyle}> <h1>岩本町オフィス</h1> </div> </InfoWindow> </GoogleMap> </LoadScript> ); };
TypeError: Cannot read property 'maps' of undefined
という実行時エラーとなります。
よって、onLoad
でマップの読み込みが完了した上でpixelOffset
の値をuseState
により作成する必要がありました。
- InfoWindow | React Google Maps Api Style Guide
- InfoWindowOptions interface - Info Window | Maps JavaScript API | Google Developers
- Size class - Coordinates | Maps JavaScript API | Google Developers
おわりに
@react-google-maps/apiを使った地図アプリでマーカーとバルーンの位置関係をいい感じに表示する方法を確認してみました。
React Hooksの仕様の理解が曖昧だったのでちゃんと理解するのに苦労しましたが、今回の確認を通じて理解が深められて良かったです。
参考
- reactjs - Property 'google' does not exist on type 'Window' - Stack Overflow
- ReactのFunction ComponentとHooks - sambaiz-net
以上